package Share;
import java.io.*;
import java.security.MessageDigest;
import java.util.Date;



public class Token {
	
	public String deleg;
	public String signer;
	public String owner;
	public int file;
	public TokenType type;
	public Boolean allowDelegation;
	public Date expiration;
	public Certificate certificate;
	private byte[] innerTokens;
	public byte[] signature;
	
	public Token(String deleg, String signer, String owner, int file, TokenType type, Boolean allowDelegate, Date expiration, Certificate cert, Token innerToken) throws IOException
	{
		this.deleg = deleg;
		this.signer = signer;
		this.owner = owner;
		this.file = file;
		this.type = type;
		this.allowDelegation = allowDelegate;
		this.expiration = expiration;
		this.certificate = cert;
		if(innerToken == null)
		{
			this.innerTokens = new byte[0];
			return;
		}
		ByteArrayOutputStream stream = new ByteArrayOutputStream();
		innerToken.serialize(new DataOutputStream(stream));
		this.innerTokens = stream.toByteArray();
	}
	
	public void serialize(DataOutputStream out) throws IOException
	{
		try
		{
			Util.write(out, deleg);
			Util.write(out, signer);
			Util.write(out, owner);
			out.writeInt(file);
			
			byte flags = (byte)(allowDelegation ? 0x08 : 0x00);
			flags |= type.ordinal();
			out.write(flags);
			
			out.writeLong(expiration.getTime());
			certificate.serialize(out);
			Util.write(out, innerTokens);
			Util.write(out, signature);
		}
		catch (IOException error)
		{
			throw error;
		}
	}

	public byte[] getDigest()
	{
		try
		{
			MessageDigest digest = MessageDigest.getInstance("SHA-512");
			digest.update(deleg.getBytes("UTF-8"));
			digest.update(signer.getBytes("UTF-8"));
			digest.update(owner.getBytes("UTF-8"));
			digest.update(Integer.toHexString(file).getBytes("UTF-8"));
			digest.update(type.name().getBytes("UTF-8"));
			digest.update(allowDelegation.toString().getBytes("UTF-8"));
			digest.update(Long.toString(expiration.getTime()).getBytes("UTF-8"));
			certificate.digest(digest);
			digest.update(innerTokens);
			return digest.digest();
		}
		catch(Exception e)
		{
			return null;
		}
	}
	
	public Token(DataInputStream in) throws IOException
	{
		deleg = Util.readString(in);
		signer = Util.readString(in);
		owner = Util.readString(in);
		file = in.readInt();
		
		byte flags = (byte)in.read();
		allowDelegation = (flags & (byte)0x80) > (byte)0;
		
		flags &= 0x7F;
		type = TokenType.values()[flags];
		
		expiration = new Date(in.readLong());
		certificate = new Certificate(in);
		innerTokens = Util.readByteArray(in);
		signature = Util.readByteArray(in);
	}
	
	public Token getNextToken()
	{
		if(innerTokens.length == 0)
			return null;
		
		ByteArrayInputStream stream = new ByteArrayInputStream(innerTokens);
		try {
			return new Token(new DataInputStream(stream));
		} catch (IOException e) {
			return null;
		}		
	}
	
}
